package com.yiban.demo.Global.Interceptor;

import com.yiban.demo.Global.AOP.Annotation.LimitRequestDuration;
import com.yiban.demo.Global.Entity.ResponseEntity;
import com.yiban.demo.Util.JsonUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Method;
import java.time.Duration;

public class LimitRequestInterceptor implements HandlerInterceptor {

    /**
     * redis key 为 LIMIT_PREFIX+访问ip+方法名构成
     * value为1（我还没想好用什么value）
     * 过期时间由 @LimitRequestDuration的 second值 决定
     */
    private final static String LIMIT_PREFIX = "limit";

    private RedisTemplate redisTemplate;

    public LimitRequestInterceptor(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        //获取间隔
        Method method = ((HandlerMethod) handler).getMethod();
        LimitRequestDuration limitRequestDuration = method
                .getAnnotation(LimitRequestDuration.class);

        if (limitRequestDuration == null){
            return true;
        }
        int seconds = limitRequestDuration.seconds();
        //获取真实ip，防止存在代理
        String ip;
        String forward = request.getHeader("x-forwarded-for");
        /**
         * request.getRemoteAddr()直接获取为上一个发送请求地址 若 A->B->service则获取的为B的地址
         * header的x-forwarded-for   若 A->B->service 则为x-forwarded-for:Aip,Bip，所以分割后获取用户ip地址
         * @see <a href ="https://www.jianshu.com/p/15f3498a7fad">HTTP 请求头中的 X-Forwarded-For</a>
         */
        ip = (forward == null ? request.getRemoteAddr() : forward.split(",")[0]);
        ValueOperations ops = redisTemplate.opsForValue();

        String keyName = LIMIT_PREFIX + ip + method.getName();
        //若存在就是拒绝访问（不执行这个Controller的方法）,上下文中获取Response对象返回错误信息
        if (ops.get(keyName) == null) {
            ops.set(keyName, 1, Duration.ofSeconds(seconds));
            return true;
        }else {
            ResponseEntity.writeBack(response, JsonUtil.defaultJsonify(ResponseEntity.Failure("操作的太快了")));
            return false;
        }

    }
}
